package com.dyna.core.utils;

import com.dyna.core.convert.BeanConverter;
import com.dyna.core.convert.DynaConversionService;
import lombok.experimental.UtilityClass;
import org.springframework.core.convert.TypeDescriptor;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.lang.Nullable;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.function.Consumer;
import java.util.stream.Collectors;

/**
 * 基于 spring ConversionService 类型转换
 *
 * @author L.cm
 */
@UtilityClass
@SuppressWarnings("unchecked")
public class ConvertUtil {

	/**
	 * Convenience operation for converting a source object to the specified targetType,
	 * where the target type is a descriptor that provides additional conversion context.
	 * {@link TypeDescriptor#forObject(Object)}.
	 * @param source the source object
	 * @param sourceType the source type
	 * @param targetType the target type
	 * @param <T> 泛型标记
	 * @return the converted value
	 * @throws IllegalArgumentException if targetType is {@code null},
	 * or sourceType is {@code null} but source is not {@code null}
	 */
	@Nullable
	public static <T> T convert(@Nullable Object source, TypeDescriptor sourceType, TypeDescriptor targetType) {
		if (source == null) {
			return null;
		}
		GenericConversionService conversionService = DynaConversionService.getInstance();
		return (T) conversionService.convert(source, sourceType, targetType);
	}

	/**
	 * Convenience operation for converting a source object to the specified targetType,
	 * where the target type is a descriptor that provides additional conversion context.
	 * Simply delegates to {@link #convert(Object, TypeDescriptor, TypeDescriptor)} and
	 * encapsulates the construction of the source type descriptor using
	 * {@link TypeDescriptor#forObject(Object)}.
	 * @param source the source object
	 * @param targetType the target type
	 * @param <T> 泛型标记
	 * @return the converted value
	 * @throws IllegalArgumentException if targetType is {@code null},
	 * or sourceType is {@code null} but source is not {@code null}
	 */
	@Nullable
	public static <T> T convert(@Nullable Object source, TypeDescriptor targetType) {
		if (source == null) {
			return null;
		}
		GenericConversionService conversionService = DynaConversionService.getInstance();
		return (T) conversionService.convert(source, targetType);
	}

	/**
	 * 转换单个对象
	 */
	public static <S, T> T convert(S source, BeanConverter<S, T> converter) {
		return source == null ? null : converter.convert(source);
	}

	/**
	 * 批量转换（顺序处理）
	 */
	public static <S, T> List<T> convertList(Collection<S> sources, BeanConverter<S, T> converter) {
		return converter.convertList(sources);
	}

	/**
	 * 并行批量转换（利用多核CPU）
	 */
	public static <S, T> List<T> convertListParallel(Collection<S> sources, BeanConverter<S, T> converter) {
		if (sources == null || sources.isEmpty())  {
			return Collections.emptyList();
		}
		return sources.parallelStream()
				.map(converter::convert)
				.collect(Collectors.toList());
	}

	/**
	 * 带批处理回调的转换（适合需要分批次处理的场景）
	 */
	public static <S, T> void convertWithBatch(Collection<S> sources,
											   BeanConverter<S, T> converter,
											   Consumer<List<T>> batchConsumer,
											   int batchSize) {
		if (sources == null || sources.isEmpty())  return;

		List<T> batch = new ArrayList<>(batchSize);
		for (S source : sources) {
			batch.add(converter.convert(source));
			if (batch.size()  >= batchSize) {
				batchConsumer.accept(batch);
				batch.clear();
			}
		}
		if (!batch.isEmpty())  {
			batchConsumer.accept(batch);
		}
	}

}
